using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;

namespace ApkInstaller.Util
{
	public class ApkResourceFinder
	{
		private const long HEADER_START = 0L;

		private static short RES_STRING_POOL_TYPE = 1;

		private static short RES_TABLE_TYPE = 2;

		private static short RES_TABLE_PACKAGE_TYPE = 512;

		private static short RES_TABLE_TYPE_TYPE = 513;

		private static short RES_TABLE_TYPE_SPEC_TYPE = 514;

		private string[] valueStringPool = null;

		private string[] typeStringPool = null;

		private string[] keyStringPool = null;

		private int package_id = 0;

		private List<string> resIdList;

		private static byte TYPE_REFERENCE = 1;

		private static byte TYPE_STRING = 3;

		private Dictionary<string, List<string>> responseMap;

		private Dictionary<int, List<string>> entryMap = new Dictionary<int, List<string>>();

		public Dictionary<string, List<string>> initialize()
		{
			byte[] data = File.ReadAllBytes("resources.arsc");
			return this.processResourceTable(data, new List<string>());
		}

		public Dictionary<string, List<string>> processResourceTable(byte[] data, List<string> resIdList)
		{
			this.resIdList = resIdList;
			this.responseMap = new Dictionary<string, List<string>>();
			Dictionary<string, List<string>> result;
			using (MemoryStream memoryStream = new MemoryStream(data))
			{
				using (BinaryReader binaryReader = new BinaryReader(memoryStream))
				{
					short num = binaryReader.ReadInt16();
					short num2 = binaryReader.ReadInt16();
					int num3 = binaryReader.ReadInt32();
					int num4 = binaryReader.ReadInt32();
					bool flag = num != ApkResourceFinder.RES_TABLE_TYPE;
					if (flag)
					{
						throw new Exception("No RES_TABLE_TYPE found!");
					}
					bool flag2 = (long)num3 != binaryReader.BaseStream.Length;
					if (flag2)
					{
						throw new Exception("The buffer size not matches to the resource table size.");
					}
					int num5 = 0;
					int num6 = 0;
					while (true)
					{
						long position = binaryReader.BaseStream.Position;
						short num7 = binaryReader.ReadInt16();
						short num8 = binaryReader.ReadInt16();
						int num9 = binaryReader.ReadInt32();
						bool flag3 = num7 == ApkResourceFinder.RES_STRING_POOL_TYPE;
						if (flag3)
						{
							bool flag4 = num5 == 0;
							if (flag4)
							{
								Debug.WriteLine("Processing the string pool ...");
								byte[] data2 = new byte[num9];
								long position2 = binaryReader.BaseStream.Position;
								binaryReader.BaseStream.Seek(position, SeekOrigin.Begin);
								data2 = binaryReader.ReadBytes(num9);
								this.valueStringPool = this.processStringPool(data2);
							}
							int num10 = num5;
							num5 = num10 + 1;
						}
						else
						{
							bool flag5 = num7 == ApkResourceFinder.RES_TABLE_PACKAGE_TYPE;
							if (!flag5)
							{
								break;
							}
                            //Debug.WriteLine("Processing package {0} ...", new object[]
                            //{
                            //    num6
                            //});
							byte[] data3 = new byte[num9];
							long position2 = binaryReader.BaseStream.Position;
							binaryReader.BaseStream.Seek(position, SeekOrigin.Begin);
							data3 = binaryReader.ReadBytes(num9);
							this.processPackage(data3);
							int num10 = num6;
							num6 = num10 + 1;
						}
						binaryReader.BaseStream.Seek(position + (long)num9, SeekOrigin.Begin);
						bool flag6 = binaryReader.BaseStream.Position == binaryReader.BaseStream.Length;
						if (flag6)
						{
							goto Block_10;
						}
					}
					throw new InvalidOperationException("Unsupported Type");
					Block_10:
					bool flag7 = num5 != 1;
					if (flag7)
					{
						throw new Exception("More than 1 string pool found!");
					}
					bool flag8 = num6 != num4;
					if (flag8)
					{
						throw new Exception("Real package count not equals the declared count.");
					}
					result = this.responseMap;
				}
			}
			return result;
		}

		private void processPackage(byte[] data)
		{
			using (MemoryStream memoryStream = new MemoryStream(data))
			{
				using (BinaryReader binaryReader = new BinaryReader(memoryStream))
				{
					short num = binaryReader.ReadInt16();
					short num2 = binaryReader.ReadInt16();
					int num3 = binaryReader.ReadInt32();
					int num4 = binaryReader.ReadInt32();
					this.package_id = num4;
					char[] array = new char[256];
					int num5;
					for (int i = 0; i < 256; i = num5)
					{
						array[i] = binaryReader.ReadChar();
						num5 = i + 1;
					}
					int num6 = binaryReader.ReadInt32();
					int num7 = binaryReader.ReadInt32();
					int num8 = binaryReader.ReadInt32();
					int num9 = binaryReader.ReadInt32();
					bool flag = num6 != (int)num2;
					if (flag)
					{
						throw new Exception("TypeStrings must immediately follow the package structure header.");
					}
                    //Debug.WriteLine("Type strings:");
					long position = binaryReader.BaseStream.Position;
					binaryReader.BaseStream.Seek((long)num6, SeekOrigin.Begin);
					byte[] data2 = binaryReader.ReadBytes((int)(binaryReader.BaseStream.Length - binaryReader.BaseStream.Position));
					binaryReader.BaseStream.Seek(position, SeekOrigin.Begin);
					this.typeStringPool = this.processStringPool(data2);
                    //Debug.WriteLine("Key strings:");
					binaryReader.BaseStream.Seek((long)num8, SeekOrigin.Begin);
					short num10 = binaryReader.ReadInt16();
					short num11 = binaryReader.ReadInt16();
					int num12 = binaryReader.ReadInt32();
					position = binaryReader.BaseStream.Position;
					binaryReader.BaseStream.Seek((long)num8, SeekOrigin.Begin);
					byte[] data3 = binaryReader.ReadBytes((int)(binaryReader.BaseStream.Length - binaryReader.BaseStream.Position));
					binaryReader.BaseStream.Seek(position, SeekOrigin.Begin);
					this.keyStringPool = this.processStringPool(data3);
					int num13 = 0;
					int num14 = 0;
					binaryReader.BaseStream.Seek((long)(num8 + num12), SeekOrigin.Begin);
					bool flag4;
					do
					{
						int num15 = (int)binaryReader.BaseStream.Position;
						short num16 = binaryReader.ReadInt16();
						short num17 = binaryReader.ReadInt16();
						int num18 = binaryReader.ReadInt32();
						bool flag2 = num16 == ApkResourceFinder.RES_TABLE_TYPE_SPEC_TYPE;
						if (flag2)
						{
							byte[] data4 = new byte[num18];
							binaryReader.BaseStream.Seek((long)num15, SeekOrigin.Begin);
							data4 = binaryReader.ReadBytes(num18);
							this.processTypeSpec(data4);
							num5 = num13;
							num13 = num5 + 1;
						}
						else
						{
							bool flag3 = num16 == ApkResourceFinder.RES_TABLE_TYPE_TYPE;
							if (flag3)
							{
								byte[] typeData = new byte[num18];
								binaryReader.BaseStream.Seek((long)num15, SeekOrigin.Begin);
								typeData = binaryReader.ReadBytes(num18);
								this.processType(typeData);
								num5 = num14;
								num14 = num5 + 1;
							}
						}
						binaryReader.BaseStream.Seek((long)(num15 + num18), SeekOrigin.Begin);
						flag4 = (binaryReader.BaseStream.Position == binaryReader.BaseStream.Length);
					}
					while (!flag4);
				}
			}
		}

		private void putIntoMap(string resId, string value)
		{
			List<string> list = null;
			bool flag = this.responseMap.ContainsKey(resId.ToUpper());
			if (flag)
			{
				list = this.responseMap[resId.ToUpper()];
			}
			bool flag2 = list == null;
			if (flag2)
			{
				list = new List<string>();
			}
			list.Add(value);
			bool flag3 = this.responseMap.ContainsKey(resId.ToUpper());
			if (flag3)
			{
				this.responseMap[resId.ToUpper()] = list;
			}
			else
			{
				this.responseMap.Add(resId.ToUpper(), list);
			}
		}

		private void processType(byte[] typeData)
		{
			using (MemoryStream memoryStream = new MemoryStream(typeData))
			{
				using (BinaryReader binaryReader = new BinaryReader(memoryStream))
				{
					short num = binaryReader.ReadInt16();
					short num2 = binaryReader.ReadInt16();
					int num3 = binaryReader.ReadInt32();
					byte b = binaryReader.ReadByte();
					byte b2 = binaryReader.ReadByte();
					short num4 = binaryReader.ReadInt16();
					int num5 = binaryReader.ReadInt32();
					int num6 = binaryReader.ReadInt32();
					Dictionary<string, int> dictionary = new Dictionary<string, int>();
					int num7 = binaryReader.ReadInt32();
					binaryReader.BaseStream.Seek((long)num2, SeekOrigin.Begin);
					bool flag = (int)num2 + num5 * 4 != num6;
					if (flag)
					{
						throw new Exception("HeaderSize, entryCount and entriesStart are not valid.");
					}
					int[] array = new int[num5];
					int num8;
					for (int i = 0; i < num5; i = num8)
					{
						array[i] = binaryReader.ReadInt32();
						num8 = i + 1;
					}
					for (int j = 0; j < num5; j = num8)
					{
						bool flag2 = array[j] == -1;
						if (!flag2)
						{
							int num9 = this.package_id << 24 | (int)b << 16 | j;
							long position = binaryReader.BaseStream.Position;
							short num10 = binaryReader.ReadInt16();
							short num11 = binaryReader.ReadInt16();
							int num12 = binaryReader.ReadInt32();
							int num13 = 1;
							bool flag3 = ((int)num11 & num13) == 0;
							if (flag3)
							{
								short num14 = binaryReader.ReadInt16();
								byte b3 = binaryReader.ReadByte();
								byte b4 = binaryReader.ReadByte();
								int num15 = binaryReader.ReadInt32();
								string text = num9.ToString("X4");
								string text2 = this.keyStringPool[num12];
								string value = null;
                                //Debug.WriteLine(string.Concat(new string[]
                                //{
                                //    "Entry 0x",
                                //    text,
                                //    ", key: ",
                                //    text2,
                                //    ", simple value type: "
                                //}));
								List<string> list = null;
								bool flag4 = this.entryMap.ContainsKey(int.Parse(text, NumberStyles.HexNumber));
								if (flag4)
								{
									list = this.entryMap[int.Parse(text, NumberStyles.HexNumber)];
								}
								bool flag5 = list == null;
								if (flag5)
								{
									list = new List<string>();
								}
								list.Add(text2);
								bool flag6 = this.entryMap.ContainsKey(int.Parse(text, NumberStyles.HexNumber));
								if (flag6)
								{
									this.entryMap[int.Parse(text, NumberStyles.HexNumber)] = list;
								}
								else
								{
									this.entryMap.Add(int.Parse(text, NumberStyles.HexNumber), list);
								}
								bool flag7 = b4 == ApkResourceFinder.TYPE_STRING;
								if (flag7)
								{
									value = this.valueStringPool[num15];
                                    //Debug.WriteLine((", data: " + this.valueStringPool[num15]) ?? "");
								}
								else
								{
									bool flag8 = b4 == ApkResourceFinder.TYPE_REFERENCE;
									if (flag8)
									{
										string text3 = num15.ToString("X4");
										dictionary.Add(text, num15);
									}
									else
									{
										value = num15.ToString();
                                        //Debug.WriteLine((", data: " + num15) ?? "");
									}
								}
								this.putIntoMap("@" + text, value);
							}
							else
							{
								int num16 = binaryReader.ReadInt32();
								int num17 = binaryReader.ReadInt32();
								for (int k = 0; k < num17; k = num8)
								{
									int num18 = binaryReader.ReadInt32();
									short num19 = binaryReader.ReadInt16();
									byte b5 = binaryReader.ReadByte();
									byte b6 = binaryReader.ReadByte();
									int num20 = binaryReader.ReadInt32();
									num8 = k + 1;
								}
                                //Debug.WriteLine(string.Concat(new string[]
                                //{
                                //    "Entry 0x",
                                //    num9.ToString("X4"),
                                //    ", key: ",
                                //    this.keyStringPool[num12],
                                //    ", complex value, not printed."
                                //}));
							}
						}
						num8 = j + 1;
					}
					HashSet<string> hashSet = new HashSet<string>(dictionary.Keys);
					foreach (string current in hashSet)
					{
						List<string> list2 = null;
						bool flag9 = this.responseMap.ContainsKey("@" + dictionary[current].ToString("X4").ToUpper());
						if (flag9)
						{
							list2 = this.responseMap["@" + dictionary[current].ToString("X4").ToUpper()];
						}
						bool flag10 = list2 != null;
						if (flag10)
						{
							foreach (string current2 in list2)
							{
								this.putIntoMap("@" + current, current2);
							}
						}
					}
				}
			}
		}

		private string[] processStringPool(byte[] data)
		{
			string[] result;
			using (MemoryStream memoryStream = new MemoryStream(data))
			{
				using (BinaryReader binaryReader = new BinaryReader(memoryStream))
				{
					short num = binaryReader.ReadInt16();
					short num2 = binaryReader.ReadInt16();
					int num3 = binaryReader.ReadInt32();
					int num4 = binaryReader.ReadInt32();
					int num5 = binaryReader.ReadInt32();
					int num6 = binaryReader.ReadInt32();
					int num7 = binaryReader.ReadInt32();
					int num8 = binaryReader.ReadInt32();
					bool flag = (num6 & 256) != 0;
					int[] array = new int[num4];
					int num9;
					for (int i = 0; i < num4; i = num9)
					{
						array[i] = binaryReader.ReadInt32();
						num9 = i + 1;
					}
					string[] array2 = new string[num4];
					for (int j = 0; j < num4; j = num9 + 1)
					{
						int num10 = num7 + array[j];
						binaryReader.BaseStream.Seek((long)num10, SeekOrigin.Begin);
						array2[j] = "";
						bool flag2 = flag;
						if (flag2)
						{
							int num11 = (int)binaryReader.ReadByte();
							bool flag3 = (num11 & 128) != 0;
							if (flag3)
							{
								num11 = ((num11 & 127) << 8) + (int)binaryReader.ReadByte();
							}
							int num12 = (int)binaryReader.ReadByte();
							bool flag4 = (num12 & 128) != 0;
							if (flag4)
							{
								num12 = ((num12 & 127) << 8) + (int)binaryReader.ReadByte();
							}
							bool flag5 = num12 > 0;
							if (flag5)
							{
								array2[j] = Encoding.UTF8.GetString(binaryReader.ReadBytes(num12));
							}
							else
							{
								array2[j] = "";
							}
						}
						else
						{
							int num13 = (int)binaryReader.ReadUInt16();
							bool flag6 = (num13 & 32768) != 0;
							if (flag6)
							{
								num13 = ((num13 & 32767) << 16) + (int)binaryReader.ReadUInt16();
							}
							bool flag7 = num13 > 0;
							if (flag7)
							{
								array2[j] = Encoding.Unicode.GetString(binaryReader.ReadBytes(num13 * 2));
							}
						}
                        //Debug.WriteLine("Parsed value: {0}", array2[j]);
						num9 = j;
					}
					result = array2;
				}
			}
			return result;
		}

		private void processTypeSpec(byte[] data)
		{
			using (MemoryStream memoryStream = new MemoryStream(data))
			{
				using (BinaryReader binaryReader = new BinaryReader(memoryStream))
				{
					short num = binaryReader.ReadInt16();
					short num2 = binaryReader.ReadInt16();
					int num3 = binaryReader.ReadInt32();
					byte b = binaryReader.ReadByte();
					byte b2 = binaryReader.ReadByte();
					short num4 = binaryReader.ReadInt16();
					int num5 = binaryReader.ReadInt32();
                    //Debug.WriteLine("Processing type spec {0}", this.typeStringPool[(int)(b - 1)]);
					int[] array = new int[num5];
					int num6;
					for (int i = 0; i < num5; i = num6)
					{
						array[i] = binaryReader.ReadInt32();
						num6 = i + 1;
					}
				}
			}
		}
	}
}
